#pragma once
#include"err.hpp"
#include<iostream>
#include<sys/types.h>
#include<sys/socket.h>
#include<cstring>
#include<cstdlib>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<functional>

namespace ns_server
{
   

    const static uint16_t default_port=8080;
    using func_t=std::function<std::string(std::string)>;
    class UdpServer
    {
    public:
    UdpServer(func_t cb,uint16_t port=default_port):service_(cb),port_(port)
    {
        std::cout << "server addr: " << " : " << port_ << std::endl;
    }
    ~UdpServer()
    {}
    void InitServer()
    {
        //1.创建套接字接口（打开网络文件）
        sock_=socket(AF_INET,SOCK_DGRAM,0);
        if(sock_<0)
        {
            std::cerr<<"create socket error:"<<strerror(errno)<<std::endl;
            exit(SOCKET_ERR);
        }
        std::cout<<"create socket succes:"<<sock_<<std::endl;
        //2.指明ip地址和端口号 
        //2.1定义sockaddr_in结构体->初始化字段->bind
        struct sockaddr_in local;
        bzero(&local,sizeof(local));//清空
        //2.1.1 16位地址类型
        local.sin_family=AF_INET;
        //2.1.2 端口号
        local.sin_port=htons(port_);//端口要发到网络当中 --主机序列转网络序列
        //2.1.3 ip 
        //字符串风格的ip地址转化成4字节的整数 “1.1.1.1”-->uint32_t
        //    主机序列->网络序列
        // 使用 ：in_addr_t inet_addr(const char* cp)
        //云服务器不能指明ip
        // local.sin_addr.s_addr=inet_addr(ip_.c_str());
        local.sin_addr.s_addr=INADDR_ANY;//bind本主机ip
        int n=bind(sock_,(struct sockaddr*)&local,sizeof(local));
        if(n<0)
        {
            std::cerr<<"bind socket error:"<<strerror(errno)<<std::endl;
            exit(BIND_ERR);
        }
    }

    void Start()
    {
        char buffer[1024];
        while (true)
        {
            //收
            struct sockaddr_in peer;
            socklen_t len=sizeof(peer);//写清楚传入缓冲区大小
            int n=recvfrom(sock_,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&len);
            if(n>0)
            {
                buffer[n]='\0';
            }
            else continue;
            //提取client信息
            std::string clientip=inet_ntoa(peer.sin_addr);
            uint16_t clientport=ntohs(peer.sin_port);
            std::cout<<clientip<<"-"<<clientport<<"get message# "<<buffer<<std::endl;
            //业务处理
            std::string response=service_(buffer);
            //发
            sendto(sock_,response.c_str(),response.size(),0,(struct sockaddr*)&peer,sizeof(peer));
        }
        
    }
    
    private:
        uint16_t port_;
        int sock_;
        func_t service_;
        //std::string ip_;//字符串风格的点分十进制
    
    };
}